#include "OpennavSearchServiceProvider.h"

/*
 * OpennavSearchCountryRequest
 */
OpennavSearchCountryRequest::OpennavSearchCountryRequest(const Osp::Base::String& name)
	: __searchString(name) { }

const Osp::Base::String& OpennavSearchCountryRequest::GetSearchString() const {
	return __searchString;
}

OpennavSearchRequestType OpennavSearchCountryRequest::GetRequestType() const  {
	return SEARCH_COUNTRY;
}

/*
 * OpennavSearchCityRequest
 */
OpennavSearchCityRequest::OpennavSearchCityRequest(const Osp::Base::String& name, int countryId)
	: __searchString(name), __countryId(countryId) { }

const Osp::Base::String& OpennavSearchCityRequest::GetSearchString() const {
	return __searchString;
}

int OpennavSearchCityRequest::GetCountryId() const {
	return __countryId;
}

OpennavSearchRequestType OpennavSearchCityRequest::GetRequestType() const  {
	return SEARCH_CITY;
}

/*
 * OpennavSearchRoadRequest
 */
OpennavSearchRoadRequest::OpennavSearchRoadRequest(const Osp::Base::String& name, int cityId)
	: __searchString(name), __cityId(cityId) { }

const Osp::Base::String& OpennavSearchRoadRequest::GetSearchString() const {
	return __searchString;
}

int OpennavSearchRoadRequest::GetCityId() const {
	return __cityId;
}

OpennavSearchRequestType OpennavSearchRoadRequest::GetRequestType() const {
	return SEARCH_ROAD;
}

/*
 * OpennavSearchCountryResult
 */
OpennavSearchCountryResult::OpennavSearchCountryResult(OpennavMap* map, opennav::SearchCountryResult& r)
	: __pMap(map), __result(r) {}

void OpennavSearchCountryResult::GetResult(int n, opennav::Country& country) {
	__pMap->GetResult(n, &__result, country);
}

int OpennavSearchCountryResult::GetCount() const {
	return __result.count();
}

OpennavSearchRequestType OpennavSearchCountryResult::GetRequestType() const  {
	return SEARCH_COUNTRY;
}

/*
 * OpennavSearchCityResult
 */
OpennavSearchCityResult::OpennavSearchCityResult(OpennavMap* map, opennav::SearchCityResult& r)
	: __pMap(map), __result(r) {}

void OpennavSearchCityResult::GetResult(int n, opennav::City& city) {
	__pMap->GetResult(n, &__result, city);
}

int OpennavSearchCityResult::GetCount() const {
	return __result.count();
}

OpennavSearchRequestType OpennavSearchCityResult::GetRequestType() const  {
	return SEARCH_CITY;
}

/*
 * OpennavSearchRoadResult
 */
OpennavSearchRoadResult::OpennavSearchRoadResult(OpennavMap* map, opennav::SearchRoadResult& r)
	: __pMap(map), __result(r) { }

void OpennavSearchRoadResult::GetResult(int n, opennav::Road& road) {
	__pMap->GetResult(n, &__result, road);
}

int OpennavSearchRoadResult::GetCount() const {
	return __result.count();
}

OpennavSearchRequestType OpennavSearchRoadResult::GetRequestType() const {
	return SEARCH_ROAD;
}

/*
 * OpennavSearchServiceProvider
 */

OpennavSearchServiceProvider::OpennavSearchServiceProvider()
	: __pMap(null), __pSearchWorker(null), __pLock(null), __kill(false), __pRequest(null), __pRequestListener(null) { }

OpennavSearchServiceProvider::~OpennavSearchServiceProvider() {
	if (__pSearchWorker != null) {
		__kill = true;
		__pSearchWorker->Join();
		delete __pSearchWorker;
		__pSearchWorker = null;
	}
	if (__pLock != null) {
		delete __pLock;
		__pLock = null;
	}
	if (__pRequest != null) {
		delete __pRequest;
		__pRequest = null;
	}
}

result OpennavSearchServiceProvider::Construct(OpennavMap* map) {
	__pMap = map;
	__pSearchWorker = new Osp::Base::Runtime::Thread();
	__pSearchWorker->Construct(L"SearchWorker", *this, Osp::Base::Runtime::Thread::DEFAULT_STACK_SIZE, Osp::Base::Runtime::THREAD_PRIORITY_LOW);
	__pSearchWorker->Start();
	__pLock = new Osp::Base::Runtime::Mutex();
	__pLock->Create();
	return E_SUCCESS;
}

void OpennavSearchServiceProvider::Search(const IOpennavSearchRequest& request, IOpennavSearchServiceListener& listener) {
	__pLock->Acquire();
	if (__pRequest != null) {
		delete __pRequest;
		__pRequest = null;
	}
	AppLogDebug("search request");
	switch (request.GetRequestType()) {
		case SEARCH_COUNTRY:
			__pRequest = new OpennavSearchCountryRequest((OpennavSearchCountryRequest&)request);
		break;
		case SEARCH_CITY:
			__pRequest = new OpennavSearchCityRequest((OpennavSearchCityRequest&)request);
		break;
		case SEARCH_ROAD:
			__pRequest = new OpennavSearchRoadRequest((OpennavSearchRoadRequest&)request);
		break;
	}
	__pRequestListener = &listener;
	__pLock->Release();
}

Osp::Base::Object* OpennavSearchServiceProvider::Run(void) {
	AppLogDebug("search worker started");
	while (__kill == false) {
		__pLock->Acquire();
		if (__pRequest != null) {
			AppLogDebug("search worker awakes");
			IOpennavSearchServiceListener* listener = __pRequestListener;
			switch (__pRequest->GetRequestType()) {
				case SEARCH_COUNTRY:
				{
					Osp::Base::String country = Osp::Base::String(((OpennavSearchCountryRequest*)__pRequest)->GetSearchString());
					if (__pRequest != null) {
						delete __pRequest;
						__pRequest = null;
					}
					__pLock->Release();
					opennav::SearchCountryResult searchresult;
					__pMap->FindCountry(country, searchresult);
					OpennavSearchCountryResult* result = new OpennavSearchCountryResult(__pMap, searchresult);
					listener->OnGeocodingRequestResultReceived(result);
				}
				break;
				case SEARCH_CITY:
				{
					Osp::Base::String city = Osp::Base::String(((OpennavSearchCityRequest*)__pRequest)->GetSearchString());
					int countryId = ((OpennavSearchCityRequest*)__pRequest)->GetCountryId();
					if (__pRequest != null) {
						delete __pRequest;
						__pRequest = null;
					}
					__pLock->Release();
					opennav::SearchCityResult searchresult;
					__pMap->FindCity(city, countryId, searchresult);
					OpennavSearchCityResult* result = new OpennavSearchCityResult(__pMap, searchresult);
					listener->OnGeocodingRequestResultReceived(result);
				}
				break;
				case SEARCH_ROAD:
				{
					Osp::Base::String road = Osp::Base::String(((OpennavSearchRoadRequest*)__pRequest)->GetSearchString());
					int cityId = ((OpennavSearchRoadRequest*)__pRequest)->GetCityId();
					if (__pRequest != null) {
						delete __pRequest;
						__pRequest = null;
					}
					__pLock->Release();
					opennav::SearchRoadResult searchresult;
					__pMap->FindRoad(road, cityId, searchresult);
					OpennavSearchRoadResult* result = new OpennavSearchRoadResult(__pMap, searchresult);
					listener->OnGeocodingRequestResultReceived(result);
				}
				break;
				default:
					__pLock->Release();
					break;
			}
		} else {
			__pLock->Release();
			Osp::Base::Runtime::Thread::GetCurrentThread()->Sleep(0);
		}
	}
	AppLogDebug("search worker terminated");
	return null;
}
